/* -------------------------------------------------------------------------
//  File        :   tiles_map.cpp
//  Author      :   Sum
//  Datet       :   2014/4/15 17:45
//  Brief       :   
//
// -----------------------------------------------------------------------*/
//
#include "stdafx.h"
#include "tiles_map.h"
#include "hgesprite.h"

tiles_map::tiles_map()
{
    m_ppPropes = NULL;
    m_ppTilesGround = NULL;
    m_ppTilesObject = NULL;
    m_nWidth = 0;
    m_nHeight = 0;
    m_nFillTile = 0;
}

tiles_map::~tiles_map()
{

}

BOOL tiles_map::init(HGE* pHGE, LPCTSTR lpszXMLPath)
{
    if (pHGE == NULL
        || lpszXMLPath == NULL)
    {
        return FALSE;
    }

    return _parseTilesXml(lpszXMLPath);
}

BOOL tiles_map::uninit()
{
    int uCount = m_nHeight * m_nWidth;
    if (m_ppTilesGround)
    {
        for (int i = 0; i < uCount; ++i)
        {
            tile_item* pTile = m_ppTilesGround[i];
            if (pTile)
            {
                delete pTile;
            }
        }
        delete []m_ppTilesGround;
        m_ppTilesGround = NULL;
    }

    if (m_ppTilesObject)
    {
        for (int i = 0; i < uCount; ++i)
        {
            object_item* pObj = m_ppTilesObject[i];
            if (pObj)
            {
                delete pObj;
            }
        }
        delete []m_ppTilesObject;
        m_ppTilesObject = NULL;
    }

    if (m_ppPropes)
    {
        for (int i = 0; i < uCount; ++i)
        {
            prop_item* pObj = m_ppPropes[i];
            if (pObj)
            {
                delete pObj;
            }
        }
        delete []m_ppPropes;
        m_ppPropes = NULL;
    }

    return TRUE;
}

BOOL tiles_map::update()
{
    return TRUE;
}

BOOL tiles_map::render()
{
    if (!_renderTiles(m_ppTilesGround)
        || !_renderTiles(m_ppTilesObject)
        || !_renderTiles(m_ppPropes))
    {
        return FALSE;
    }

    return TRUE;
}

BOOL tiles_map::_parseTilesXml(LPCTSTR lpszFilePath)
{
    BOOL bReturn = FALSE;
    TiXmlElement* pRoot = NULL;
    TiXmlDocument doc;
    CString cstrPath(lpszFilePath);

    if (lpszFilePath == NULL)
    {
        goto exit;
    }

    if (!doc.LoadFile(CW2A(lpszFilePath).m_psz))
    {
        goto exit;
    }

    pRoot = _parseTilesBaseXml(doc);
    if (pRoot == NULL)
    {
        goto exit;
    }

    if (!_createTilesMap(m_ppTilesGround)
        || !_createObjectMap(m_ppTilesObject)
        || !_createPropMap(m_ppPropes))
    {
        goto exit;
    }

    for (TiXmlElement* pNote = pRoot->FirstChildElement();
        pNote != NULL;
        pNote = pNote->NextSiblingElement())
    {
        _parseTilesXmlGround(pNote);
        _parseTilesXmlObject(pNote);
    }

    bReturn = TRUE;
exit:
    return bReturn;
}

BOOL tiles_map::_parseTilesXmlItem(tile_xml_item& item, TiXmlElement* pNote)
{
    if (pNote == NULL)
    {
        return FALSE;
    }

    CString cstrItemName = CA2W(pNote->ValueStr().c_str()).m_psz;
    if (cstrItemName.CompareNoCase(L"i") != 0)
    {
        return FALSE;
    }

    if (pNote->Attribute("texid", &item.id) == NULL
        || pNote->Attribute("x", &item.x) == NULL
        || pNote->Attribute("y", &item.y) == NULL)
    {
        return FALSE;
    }

    return TRUE;
}


BOOL tiles_map::_createPropMap(prop_item**& ppProps)
{
    if (ppProps)
    {
        delete []ppProps;
    }

    int uCount = m_nWidth * m_nHeight;
    ppProps = new prop_item*[uCount];
    for (int i = 0; i < uCount; ++i)
    {
        ppProps[i] = NULL;
    }
    return TRUE;
}

BOOL tiles_map::_createTilesMap(tile_item**& ppTiles)
{
    if (ppTiles)
    {
        delete []ppTiles;
    }

    int uCount = m_nWidth * m_nHeight;
    ppTiles = new tile_item*[uCount];
    
    hgeSprite* tilesSprite = tiles_pool::Instance().get(m_nFillTile);
    for (int i = 0; i < uCount; ++i)
    {
        if (tilesSprite)
        {
            tile_item* pTile = new tile_item;
            pTile->tilesSprite = tilesSprite;
            ppTiles[i] = pTile;
        }
        else
        {
            ppTiles[i] = NULL;
        }
    }

    return TRUE;
}

TiXmlElement* tiles_map::_parseTilesBaseXml(TiXmlDocument& doc)
{
    BOOL bReturn = FALSE;
    TiXmlElement* pRoot = NULL;
    CString cstrRootName;

    pRoot = doc.RootElement();
    if (pRoot == NULL)
    {
        goto exit;
    }

    cstrRootName = CA2W(pRoot->ValueStr().c_str()).m_psz;
    if (cstrRootName.IsEmpty()
        || cstrRootName.CompareNoCase(L"map") != 0)
    {
        goto exit;
    }

    if (pRoot->Attribute("width", &m_nWidth) == NULL
        || pRoot->Attribute("height", &m_nHeight) == NULL)
    {
        goto exit;
    }
    pRoot->Attribute("fill", &m_nFillTile);

exit:
    return pRoot;
}

BOOL tiles_map::_parseTilesXmlGround(TiXmlElement* pChildNote)
{
    if (!pChildNote)
    {
        return FALSE;
    }

    CString cstrItemName = CA2W(pChildNote->ValueStr().c_str()).m_psz;
    if (cstrItemName.CompareNoCase(L"ground") != 0)
    {
        return FALSE;
    }

    for (TiXmlElement* pNote = pChildNote->FirstChildElement();
        pNote != NULL;
        pNote = pNote->NextSiblingElement())
    {
        tile_xml_item pItem = {0};
        if (!_parseTilesXmlItem(pItem, pNote))
        {
            continue;
        }

        hgeSprite* tilesSprite = tiles_pool::Instance().get(pItem.id);
        if (tilesSprite)
        {
            if (m_ppTilesGround[pItem.y * m_nWidth + pItem.x] == NULL)
            {
                tile_item* pTile = new tile_item;
                m_ppTilesGround[pItem.y * m_nWidth + pItem.x] = pTile;
            }
            else
            {
                m_ppTilesGround[pItem.y * m_nWidth + pItem.x]->texid = pItem.id;
                m_ppTilesGround[pItem.y * m_nWidth + pItem.x]->tilesSprite = tilesSprite;
            }
        }
    }

    return TRUE;
}

BOOL tiles_map::_parseTilesXmlObject(TiXmlElement* pChildNote)
{
    if (!pChildNote)
    {
        return FALSE;
    }

    CString cstrItemName = CA2W(pChildNote->ValueStr().c_str()).m_psz;
    if (cstrItemName.CompareNoCase(L"object") != 0)
    {
        return FALSE;
    }

    for (TiXmlElement* pNote = pChildNote->FirstChildElement();
        pNote != NULL;
        pNote = pNote->NextSiblingElement())
    {
        object_item* pItem = new object_item;
        if (!_parseObjectXmlItem(*pItem, pNote))
        {
            delete pItem;
            continue;
        }

        hgeSprite* pSprite = tiles_pool::Instance().get(pItem->texid);
        if (pSprite)
        {
            pItem->tilesSprite = pSprite;
            m_ppTilesObject[pItem->y * m_nWidth + pItem->x] = pItem;
        }
        else
        {
            delete pItem;
        }
    }

    return TRUE;
}

BOOL tiles_map::_parseObjectXmlItem(object_item& item, TiXmlElement* pNote)
{
    if (pNote == NULL)
    {
        return FALSE;
    }

    CString cstrItemName = CA2W(pNote->ValueStr().c_str()).m_psz;
    if (cstrItemName.CompareNoCase(L"i") != 0)
    {
        return FALSE;
    }

    item.eventName = CA2W(pNote->Attribute("event")).m_psz;
    pNote->Attribute("block", &item.block);

    if (pNote->Attribute("texid", &item.texid) == NULL
        || pNote->Attribute("x", &item.x) == NULL
        || pNote->Attribute("y", &item.y) == NULL)
    {
        return FALSE;
    }

    return TRUE;
}

BOOL tiles_map::_createObjectMap(object_item**& ppTiles)
{
    if (ppTiles)
    {
        delete []ppTiles;
    }

    int uCount = m_nWidth * m_nHeight;
    ppTiles = new object_item*[uCount];
    for (int i = 0; i < uCount; ++i)
    {
        ppTiles[i] = NULL;
    }

    return TRUE;
}

tiles_map::object_item** tiles_map::getObjects()
{
    return m_ppTilesObject;
}

BOOL tiles_map::saveMap(LPCTSTR lpszPath)
{
    if (!lpszPath)
    {
        return FALSE;
    }

    TiXmlDocument doc;
    TiXmlDeclaration* pDeclaretion = new TiXmlDeclaration("1.0", "UTF-8", "");
    if (!pDeclaretion)
    {
        return FALSE;
    }

    doc.LinkEndChild(pDeclaretion);

    TiXmlElement* pRoot = _createXmlMapInfo();
    if (!pRoot)
    {
        return FALSE;
    }

    TiXmlNode* pMap = doc.LinkEndChild(pRoot);
    if (!pMap)
    {
        return FALSE;
    }

    if (!_createXmlGround(pRoot)
        || !_createXmlObject(pRoot))
    {
        return FALSE;
    }

    std::string strSaveFilePath = CW2A(lpszPath).m_psz;
    return doc.SaveFile(strSaveFilePath);
}

BOOL tiles_map::_createXmlGround(TiXmlElement* pPrentsNote)
{
    TiXmlElement* pNote = new TiXmlElement("ground");
    if (!pNote)
    {
        return FALSE;
    }

    TiXmlNode* pGroundItem = pPrentsNote->LinkEndChild(pNote);
    if (!pGroundItem)
    {
        return FALSE;
    }

    for (int nHeightIndex = 0; nHeightIndex < m_nHeight; ++nHeightIndex)
    {
        for (int nWidhtIndex = 0; nWidhtIndex < m_nWidth; ++nWidhtIndex)
        {
            TiXmlElement* pItem = new TiXmlElement("i");
            tile_item* pTileItem = m_ppTilesGround[nHeightIndex * m_nWidth + nWidhtIndex];
            if (pItem
                && pTileItem
                && pTileItem->tilesSprite
                && pTileItem->texid != 0)
            {
                pItem->SetAttribute("x", nWidhtIndex);
                pItem->SetAttribute("y", nHeightIndex);
                pItem->SetAttribute("texid", pTileItem->texid);
                pGroundItem->LinkEndChild(pItem);
            }
            else
            {
                delete pItem;
            }
        }
    }

    return TRUE;
}

BOOL tiles_map::_createXmlObject(TiXmlElement* pPrentsNote)
{
    TiXmlElement* pNote = new TiXmlElement("object");
    if (!pNote)
    {
        return FALSE;
    }

    TiXmlNode* pObjectItem = pPrentsNote->LinkEndChild(pNote);
    if (!pObjectItem)
    {
        return FALSE;
    }

    for (int nHeightIndex = 0; nHeightIndex < m_nHeight; ++nHeightIndex)
    {
        for (int nWidhtIndex = 0; nWidhtIndex < m_nWidth; ++nWidhtIndex)
        {
            TiXmlElement* pItem = new TiXmlElement("i");
            object_item* pTileItem = m_ppTilesObject[nHeightIndex * m_nWidth + nWidhtIndex];
            if (pItem && pTileItem && pTileItem->tilesSprite)
            {
                pItem->SetAttribute("x", nWidhtIndex);
                pItem->SetAttribute("y", nHeightIndex);
                pItem->SetAttribute("event", CW2A(pTileItem->eventName).m_psz);
                pItem->SetAttribute("block", pTileItem->block);
                pItem->SetAttribute("texid", pTileItem->texid);
                pObjectItem->LinkEndChild(pItem);
            }
            else
            {
                delete pItem;
            }
        }
    }

    return TRUE;
}

TiXmlElement* tiles_map::_createXmlMapInfo()
{
    TiXmlElement* pRoot = new TiXmlElement("map");
    if (!pRoot)
    {
        return NULL;
    }

    pRoot->SetAttribute("width", m_nWidth);
    pRoot->SetAttribute("height", m_nHeight);
    pRoot->SetAttribute("fill", m_nFillTile);
    pRoot->SetAttribute("size", TILES_SIZE);
    return pRoot;
}
